package com.bluexmicro.ota

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanResult
import android.content.Context
import android.util.Log
import com.bluexmicro.android.ota.OtaManager
import com.bluexmicro.android.ota.OtaParamHelper.getBluetoothDevice
import com.bluexmicro.android.ota.OtaParamHelper.loadBinData
import com.bluexmicro.android.ota.entity.OtaTask
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import java.io.File
import java.math.BigInteger

/**
 * 1. 在你的 root build.gradle 添加 maven { url 'https://jitpack.io' }
 * 2. implementation 'com.gitee.bluexmicro:Android-OTA-Library:1.0.5' //replace latest version
 */
class KotlinExample {

    private val otaManager: OtaManager

    constructor(context: Context, device: BluetoothDevice) {
        otaManager = OtaManager(context, device)
    }

    constructor(context: Context, scanResult: ScanResult) {
        otaManager = OtaManager(context, scanResult.device)
    }

    constructor(context: Context, macAddress: String) {
        val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
        manager ?: throw IllegalArgumentException("蓝牙不可用")
        val adapter = manager.adapter ?: throw IllegalArgumentException("蓝牙未开启或者不可用")
        require(BluetoothAdapter.checkBluetoothAddress(macAddress)) { "蓝牙地址格式不正确" }
        val device = adapter.getRemoteDevice(macAddress)
            ?: //1. 在此之前宿主app未进行扫描或者扫描时未发现此设备
            //2. 权限、位置信息等
            throw IllegalArgumentException("找不到设备")
        otaManager = OtaManager(context, device)
    }

    ///////////////////////////////////////////////////////////////////////////
    // OTA
    ///////////////////////////////////////////////////////////////////////////

    /**
     * @param scope：
     * 在 ViewModel 中：viewModelScope,
     * 在 Activity，Fragment 中：lifecycleScope
     * 在 Compose 用： LaunchedEffect等
     */
    private fun startOta(scope: CoroutineScope, task: OtaTask) {
        val job = scope.launch {
            otaManager.startOta(task).catch {
                //开始传输数据前发生了错误
                Log.e("TAG", "error: ${it.message}")
            }.collect {
                //otaState包含了：结果，进度，开始时间，结束时间等信息
                Log.e("TAG", "error: $it")
            }
        }
        //job.cancel()//中途取消
    }

    private fun startFastOta(scope: CoroutineScope, tasks: List<OtaTask>) {
        val job = scope.launch {
            otaManager.startFastOta(tasks).catch {
                //开始传输数据前发生了错误
                Log.e("TAG", "error: ${it.message}")
            }.collect {
                //otaState包含了：index,结果，进度，开始时间，结束时间等信息
                Log.e("TAG", "error: $it")
            }
        }
        //job.cancel()//中途取消
    }

    //是否资源，执行后manager不可用，需重新创建对象。一般用于离开OTA页面时
    fun release() {
        otaManager.release()
    }

    ///////////////////////////////////////////////////////////////////////////
    // 关于参数的初始化
    ///////////////////////////////////////////////////////////////////////////
    /**
     * @param file       从服务器下载的（获取嵌入式工程师提供的）固件（firmware.bin）
     * @param hexAddress 16进制地址（example：E33000），如果为null，则代表默认地址，（从服务器获取，或者询问你们的嵌入式工程师）
     */
    fun buildOtaTask(file: File?, hexAddress: String?): OtaTask? {
        val data = loadBinData(file!!) ?: return null
        val address: BigInteger? = try {
            if (hexAddress.isNullOrEmpty()) {
                null
            } else {
                BigInteger(hexAddress, 16)
            }
        } catch (ignore: Exception) {
            // hexAddress 格式不对
            null
        }
        return OtaTask(data, address)
    }

    /**
     * @param bytes      从服务器下载的数据
     * @param hexAddress 16进制地址（example：E33000），如果为null，则代表默认地址，（从服务器获取，或者询问你们的嵌入式工程师）
     */
    fun buildOtaTask(bytes: ByteArray, hexAddress: String?): OtaTask? {
        val address: BigInteger? = try {
            if (hexAddress.isNullOrEmpty()) {
                null
            } else {
                BigInteger(hexAddress, 16)
            }
        } catch (ignore: Exception) {
            // hexAddress 格式不对
            null
        }
        return OtaTask(bytes, address)
    }

    fun getDeviceByMacAddress(context: Context?, macAddress: String): BluetoothDevice? {
        return getBluetoothDevice(context!!, macAddress)
    }
}